////////////////////////////////////////////////////////////////
///
/// File: NVIDIALib.h
/// Author: Cristian Dittamo
/// Last update: 11 Dec 2009
/// Description: This file contains the definition of the 
///              main functions needed for invoking nVidia driver functions.
/// To do: 
/// ------------------------------------------------------------
/// Copyright (c) 2009 Cristian Dittamo (dittamo@di.unipi.it)
/// 
/// The use and distribution terms for this software are 
/// contained in the file named license.txt, which can be found 
/// in the root of this distribution.
/// By using this software in any fashion, you are agreeing to 
/// be bound by the terms of this license.
///
/// You must not remove this notice, or any other, from this
/// software.
/// ------------------------------------------------------------
////////////////////////////////////////////////////////////////
// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the NVIDIALIB_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// NVIDIALIB_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#define NVIDIALIB_API __declspec(dllexport)
#define CALLTYPE __stdcall

#define ERR NULL

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>

// includes, CUDA
#include <cuda.h>
#include <cutil_inline.h>
#include <cuda_runtime_api.h>
#include <cutil.h>

using namespace std;

class NVIDIALIB_API CUDAComp
{
public:
	CUDAComp(int num_args, int num_funcs );
	~CUDAComp();
	CUmodule* CreateModule(char* ptxFile);
	void DeleteModule();
	CUcontext* CreateContext();
	void DeleteContext();
	CUfunction* AddFunction(char* kernel_name);
	int GPUMemAlloc(int mem_size);
	//////
	void MemCpyH2D(int dev_index, void* srcHost, int mem_size);
	void MemCpyD2H(int dev_index, void* destHost, int mem_size);

	int SetParamI(CUfunction* fun, int offset, int dev_index);
	int SetParamV(CUfunction* fun, int offset, int dev_index);
	//////
private:
	int dptrIndex;
	int max_args;
	int funcIndex;
	int max_funcs;
	CUcontext cuContext;
	CUmodule cuModule;
	CUfunction** funcs;
	CUdeviceptr** dptr;
	CUdevice cuDevice;
};

extern "C" NVIDIALIB_API void CALLTYPE GetDevices(int*);
extern "C" NVIDIALIB_API CUDAComp* CALLTYPE InitEnv(int num_args, int num_funcs);
extern "C" NVIDIALIB_API void CALLTYPE Exit(CUDAComp* compute);

extern "C" NVIDIALIB_API CUcontext* CALLTYPE createContext(CUDAComp* compute);
extern "C" NVIDIALIB_API void CALLTYPE deleteContext(CUDAComp* compute);

extern "C" NVIDIALIB_API CUmodule* CALLTYPE LoadBin(CUDAComp* compute, char* ptxFile);
extern "C" NVIDIALIB_API void CALLTYPE UnLoadModule(CUDAComp* compute);
extern "C" NVIDIALIB_API CUfunction* CALLTYPE LoadFunc(CUDAComp* compute, char* kernel_name);

extern "C" NVIDIALIB_API int CALLTYPE MAllocOnGPU ( CUDAComp* compute, int mem_size );
extern "C" NVIDIALIB_API void CALLTYPE MFree(int dev_index);

//extern "C" NVIDIALIB_API void CALLTYPE MCpyCPU2GPU(CUDAComp* compute, int devPtrIndex, void* srcHost, int mem_size);
//extern "C" NVIDIALIB_API void CALLTYPE MCpyGPU2CPU(CUDAComp* compute, void* dstHost, int devPtrIndex, int mem_size);
extern "C" NVIDIALIB_API void CALLTYPE MCpyCPU2GPU(CUDAComp* compute, int dev_index, void* srcHost, int mem_size);
extern "C" NVIDIALIB_API void CALLTYPE MCpyGPU2CPU(CUDAComp* compute, void* dstHost, int dev_index, int mem_size);

extern "C" NVIDIALIB_API int CALLTYPE SetParamI(CUDAComp* compute, CUfunction* fun, int offset, int value);
extern "C" NVIDIALIB_API int CALLTYPE SetParamV(CUDAComp* compute, CUfunction* fun, int offset, int dev_index);

//extern "C" NVIDIALIB_API void CALLTYPE SetParamI(CUfunction* fun, int* offset, int value);
//extern "C" NVIDIALIB_API void CALLTYPE SetParamSetV(CUfunction* fun, int* offset, int dev_index);
extern "C" NVIDIALIB_API void CALLTYPE SetParamSize(CUfunction* fun, int mem_size);

extern "C" NVIDIALIB_API  int CALLTYPE SetBlockShape(CUfunction* fun, int x, int y, int z);

extern "C" NVIDIALIB_API void CALLTYPE LaunchGrid(CUfunction* fun, int gridWidth, int gridHeight);

extern "C" NVIDIALIB_API int CALLTYPE GetDevPrpVersion(CUdevice devId, int* major, int* minor);
extern "C" NVIDIALIB_API int CALLTYPE GetDevPrpPROCNUM(CUdevice devId, int* multiProcessorCount);
